#define FUSE_USE_VERSION 26

#include <string.h>
#include <stdio.h>
#include <fuse.h>
#include <errno.h>
#include <stdlib.h>
#include <syslog.h>
#include <assert.h>
#include <vector>
#include <libgen.h>
#include <time.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <mysql/mysql.h>

#define QUERY_BUF_SIZE 4096

/*------------------------------------------------------------------------------
Root (relative)
	/

Music Filesystem Organization
	/music
	/music/playlists
	/music/artists
	/music/artists/<artist>
	/music/artists/<artist>/albums
	/music/artists/<artist>/albums/<album>
	/music/artists/<artist>/songs
	/music/albums
	/music/albums/<album>
	/music/songs
	/music/genres
	/music/genres/<genre>
	/music/genres/<genre>/artists
	/music/genres/<genre>/artists/<artist>
	/music/genres/<genre>/albums
	/music/genres/<genre>/albums/<album>
	/music/genres/<genre>/songs

Video Filesystem Organization
	/video
	/video/movies
	/video/videoclips
	/video/videoclips/<artist>
	
Pictures Filesystem Organization
	/pictures

------------------------------------------------------------------------------*/

// #define is_root(path)	(strcmp(path, "/")==0)

MYSQL db;
// TODO write queries

// /music/playlists/
void query_get_playlists(char* q) {
	return;
}

// /music/artists/
void query_get_artists(char* q) {
	strncpy (
		q,
		"SELECT art.name AS artist FROM (Artists art INNER JOIN \
		Audio a ON a.artist = art.id)",
		strlen(q)
	);
}

// /music/artists/<artist>/albums/
void query_get_albums_by_artist(const char* artist, char* q) {
	char* buf = (char*)malloc(QUERY_BUF_SIZE);
	sprintf (
		buf, 
		"SELECT alb.name AS album FROM ((Artists art INNER JOIN \
		Audio a ON a.artist = art.id) INNER JOIN \
		Albums alb ON a.album = alb.id) WHERE \
		art.name = \'%s\'", 
		artist
	);
	strncpy (q, buf, strlen(buf));
	free (buf);
}

// /music/artists/<artist>/albums/<album>/
void query_get_songs_by_artist_and_album(const char* artist, const char* album, char* q) {
	char* buf = (char*)malloc(QUERY_BUF_SIZE);
	sprintf (
		buf,
		"SELECT f.filename AS song FROM ((((Artists art INNER JOIN \
		Audio a ON a.artist = art.id) INNER JOIN \
		Albums alb on a.album = alb.id) INNER JOIN \
		Files f ON a.hddFile = f.id) INNER JOIN \
		FileTypes ft ON f.type = ft.id) WHERE \
		art.name = \'%s\' AND alb.name = \'%s\' AND ft.name=\'audio\'",
		artist, album
	);
	strncpy (q, buf, strlen(q));
	free (buf);
}

// /music/artists/<artist>/songs/
void query_get_songs_by_artist(const char* artist, char* q) {
	char* buf = (char*)malloc(QUERY_BUF_SIZE);
	sprintf (
		buf,
		"SELECT f.filename AS song FROM (((Artists art INNER JOIN \
		Audio a ON a.artist = art.id) INNER JOIN \
		Files f ON a.hddFile = f.id) INNER JOIN \
		FileTypes ft ON f.type = ft.id) WHERE \
		art.name = \'%s\' AND ft.name=\'audio\'",
		artist
	);
	strncpy (q, buf, strlen(q));
	free (buf);
}

// /music/albums/
void query_get_albums(char* q) {
	strncpy (
		q, 
		"SELECT alb.name AS album FROM (Albums alb INNER JOIN \
		Audio a ON a.album = alb.id)", 
		strlen(q)
	);
}

// /music/genres/
void query_get_genres(char* q) {
	strncpy (
		q, 
		"SELECT gen.name AS genre FROM (AudioGenres gen INNER JOIN \
		Audio a ON a.genre = gen.id)", 
		strlen(q)
	);
}

// /music/genres/<genre>/artists
void query_get_artists_by_genre (const char* genre, char* q) {
	char* buf = (char*)malloc(QUERY_BUF_SIZE);
	sprintf (
		buf,
		"SELECT art.name AS artist FROM ((Artists art INNER JOIN \
		Audio a ON a.artist = art.id) INNER JOIN \
		AudioGenres gen ON a.genre = gen.id) WHERE \
		gen.name = \'%s\'",
		genre
	);
	strncpy (q, buf, strlen(q));
	free (buf);
}

// /music/genres/<genre>/artists/<artist>/_<songs>_
void query_get_songs_by_genre_and_artist (const char* genre, const char* artist, char* q) {
	char* buf = (char*)malloc(QUERY_BUF_SIZE);
	sprintf (
		buf,
		"SELECT f.filename AS song FROM ((((Artists art INNER JOIN \
		Audio a ON a.artist = art.id) INNER JOIN \
		AudioGenres gen ON a.genre = gen.id) INNER JOIN \
		Files f ON a.hddFile = f.id) INNER JOIN \
		FileTypes ft ON f.type = ft.id) WHERE \
		art.name = \'%s\' AND gen.name = \'%s\' AND ft.name=\'audio\'",
		artist, genre
	);
	strncpy (q, buf, strlen(q));
	free (buf);
}

// /music/genres/<genre>/albums/<album>/_<songs>_
void query_get_songs_by_genre_and_album (const char* genre, const char* album, char* q) {
	char* buf = (char*)malloc(QUERY_BUF_SIZE);
	sprintf (
		buf,
		"SELECT f.filename AS song FROM ((((Albums alb INNER JOIN \
		Audio a ON a.album = alb.id) INNER JOIN \
		AudioGenres gen ON a.genre = gen.id) INNER JOIN \
		Files f ON a.hddFile = f.id) INNER JOIN \
		FileTypes ft ON f.type = ft.id) WHERE \
		alb.name = \'%s\' AND gen.name = \'%s\' AND ft.name=\'audio\'",
		album, genre
	);
	strncpy (q, buf, strlen(q));
	free (buf);
}

// /music/genres/<genre>/songs
void query_get_songs_by_genre (const char* genre, char* q) {
	char* buf = (char*)malloc(QUERY_BUF_SIZE);
	sprintf (
		buf,
		"SELECT f.filename AS song FROM (((AudioGenres INNER JOIN Audio ON \
		AudioGenres gen ON a.genre = gen.id) INNER JOIN \
		Files f ON a.hddFile = f.id) INNER JOIN \
		FileTypes ft ON f.type = ft.id) WHERE \
		gen.name = \'%s\' AND ft.name=\'audio\'",
		genre
	);
	strncpy (q, buf, strlen(q));
	free (buf);
}

// /video
// nothing

// /video/movies
void query_get_movies(char* q) {
	strncpy (
		q,
		"SELECT f.filename AS movie FROM ((Video v INNER JOIN Files f ON \
		v.hddFile = f.id) INNER JOIN FileTypes ft ON \
		f.type = ft.id) WHERE ft.name=\'movie\'",
		strlen(q)
	);
}

// /video/videoclips
void query_get_videoclips(char* q) {
	strncpy (
		q,
		"SELECT f.filename AS movie FROM ((Video v INNER JOIN Files f ON \
		v.hddFile = f.id) INNER JOIN FileTypes ft ON \
		f.type = ft.id) WHERE ft.name=\'videoclip\'",
		strlen(q)
	);
}

// /video/videoclips/<artist>/_<videoclips>_
void query_get_videoclips_by_artist(const char* artist, char* q) {
	return;
}

// /pictures
void query_get_pictures(char* q) {
	strncpy (
		q,
		"SELECT f.filename AS movie FROM ((Photo p INNER JOIN Files f ON \
		p.hddFile = f.id) INNER JOIN FileTypes ft ON \
		f.type = ft.id) WHERE ft.name = \'video\'",
		strlen(q)
	);
}

// delete file
// !cascades
void query_delete_file(char* filename, char* q) {
	char* buf = (char*)malloc(QUERY_BUF_SIZE);
	sprintf (
		buf,
		"DELETE FROM Files f WHERE f.filename = \'%s\'",
		filename
	);
	strncpy (q, buf, strlen(q));
	free (buf);
}


////////////////////////////////////////////////////////////////////////////////
// path: /
int is_root (const char *path) {
	return (strcmp (path, "/") == 0);
}

int is_in_root (const char* path) {
	// the first character is "/"
	// the second character should not be zero
	if (path[1] == 0) {
		return 0;
	}
	// no "/" in path + 1
	if (strtok ((char*)((void*)(path + 1)), "/")) {
		return 0;
	}
	
	return 1;
}

///////////////////////////////////////////////////////////////////
// path: /music
int is_music (const char *path) {
	return (strcmp (path, "/music") == 0);
}

int is_in_music (const char* path) {
	// begins with "/music/"
	if (! (strstr (path, "/music/") == path)) {
		return 0;
	}
	// skip two "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 2; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// *p should be nonempty
	if (*p == 0) {
		return 0;
	}
	// p must not contain another "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

////////////////////////////////////////////////////////////////////////////////
// path: /music/playlists
int is_music_playlists (const char *path) {
	return (strcmp (path, "/music/playlists") == 0);
}

int is_in_music_playlists (const char* path) {
	// begins with "/playlists/"
	if (! (strstr (path, "/playlists/") == path)) {
		return 0;
	}
	// skip two "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 2; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// *p should be nonempty
	if (*p == 0) {
		return 0;
	}
	// p must not contain another "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

////////////////////////////////////////////////////////////////////////////////
// path: /music/artists
int is_music_artists (const char *path) {
	return (strcmp (path, "/music/artists") == 0);
}

int is_in_music_artists (const char* path) {
	// begins with "/music/artists/"
	if (! (strstr (path, "/music/artists") == path)) {
		return 0;
	}
	// skip three "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// *p should be nonempty
	if (*p == 0) {
		return 0;
	}
	// p must not contain another "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

////////////////////////////////////////////////////////////////////////////////
// path: /music/artists/<artist>
int is_music_artists_artist (const char* path) {
	// begins with "/music/artists/"
	if ( !(strstr (path, "/music/artists/") == path)) {
		return 0;
	}
	// skip three "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// there should not be another "/"
	if (strtok (p, "/")) {
		return 0;
	}
	// p should not be empty
	if (*p == 0) {
		return 0;
	}
	
	return 1;
}

int is_in_music_artists_artist (const char* path) {
	// begins with "/music/artists/"
	if ( !(strstr (path, "/music/artists/") == path)) {
		return 0;
	}
	// skip four "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// there should not be another "/" in p
	if (strtok (p, "/")) {
		return 0;
	}
	// *p should be nonempty
	if (*p == 0) {
		return 0;
	}
	
	return 1;
}

// get: <artist>
char* get_artist_from_music_artists_artist (const char* path) {
	char* artist;
	// skip three "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
	}
	int len = strlen(p) + 1;
	artist = (char*)malloc(len);
	strncpy(artist, p, len - 1);
		
	return artist;
}

////////////////////////////////////////////////////////////////////////////////
// path: /music/artists/<artist>/albums
int is_music_artists_artist_albums (const char *path) {
	// contains "/music/artists" at the beginning
	if( !(strstr (path, "/music/artists") == path)) {
		return 0;
	}
	// the last string past the last '/' is "albums"
	if( !(strcmp (strrchr (path, '/'), "albums") == 0)) {
		return 0;
	}
	// exactly four "/" in path
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// no other "/" must exist
	if ( strtok (p, "/")) {
		return 0;
	}
	return 1;
}

int is_in_music_artists_artist_albums (const char *path) {
	// contains "/music/artists" at the beginning
	if( !(strstr (path, "/music/artists") == path)) {
		return 0;
	}
	// the last string past the last '/' is "albums"
	if( !(strcmp (strrchr (path, '/'), "albums") == 0)) {
		return 0;
	}
	// skip four "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// p now points to "albums/_songs_"
	if (! (strstr (p, "albums/") == p)) {
		return 0;
	}
	// skip one "/"
	p = strtok (p, "/");
	if (!p) {
		return 0;
	}
	// *p should be nonempty
	if (*p == 0) {
		return 0;
	}
	// there should be no other "/' in p
	if (strtok (p, "/")) {
		return 0;
	}
	
	// *p should not be zero 
	if (*p == 0) {
		return 0;
	}
	
	return 1;
}

// get: <artist>
char* get_artist_from_music_artists_artist_albums (const char* path) {
	int len;
	int beg;
	char* artist;
	// artist name length
	len = strlen(path) - (strlen("/music/artists/") + strlen("albums")) + 1;
	artist = (char*)malloc(len);
	// start index of <artist>
	beg = strlen("/music/artists/");
	strncpy (artist, path + beg, len - 1);
	// TODO mai trebuie zero terminator ?
	
	return artist;
}

////////////////////////////////////////////////////////////////////////////////
// path: /music/artists/<artist>/albums/<album>
int is_music_artists_artist_albums_album (const char* path) {
	// contains "/music/artists" at the beginning
	if( !(strstr (path, "/music/artists") == path)) {
		return 0;
	}
	char* albums_album = (char*)((void*)path);
	// skip the string "/" four times
	for (int i = 0; i < 4; i++) {
		albums_album = strtok (albums_album, "/");
		if (!albums_album) {
			return 0;
		} 
	}
	// at this point albums_album == "albums/<album>"
	// contains "album/" at the beginning
	if ( !(strstr (albums_album, "album/") == albums_album)) {
		return 0;
	}
	// contains only one '/'
	// the position of the first occurence = the position of the last occurence
	char* pos1 = strchr (albums_album, '/');
	char* pos2 = strrchr (albums_album, '/');
	if ( (pos1 == NULL) || (pos1 != pos2) ) {
		return 0;
	}
	// redundancy check: exactly five "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 5; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// there is no other "/" left in the string
	if ( strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

int is_in_music_artists_artist_albums_album (const char* path) {
	// contains "/music/artists" at the beginning
	if( !(strstr (path, "/music/artists") == path)) {
		return 0;
	}
	char* p = (char*)((void*)path);
	// skip the string "/" four times
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		} 
	}
	// at this point albums_album == "albums/<album>"
	// contains "album/" at the beginning
	if ( !(strstr (p, "album/") == p)) {
		return 0;
	}
	// skip two "/"
	for (int i = 0; i < 2; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		} 
	}
	// p should not contain another "/"
	if (strtok (p, "/")) {
		return 0;
	}
	// *p should not be zero
	if (*p == 0) {
		return 0;
	}

	return 1;	
}

// get: <artist>
char* get_artist_from_music_artists_artist_albums_album (const char* path) {
	int len;
	char* artist;
	char* a = (char*)((void*)path);
	// skip three "/"
	for (int i = 0; i < 3; i++) {
		a = strtok (a, "/");
	}
	// length given by the next occurence of '/'
	len = a - strchr (a, '/') + 1;
	artist = (char*)malloc(len);
	strncpy (artist, a, len - 1);
	
	return artist;
}

// get: <album>
char* get_album_from_music_artists_artist_albums_album (const char* path) {
	int len;
	char* album;
	char* a;
	// skip five "/"
	for (int i = 0; i < 5; i++) {
		a = strtok(a, "/");
	}
	// <album> is now pointed to by a
	len = strlen(a) + 1;
	album = (char*)malloc(len);
	strncpy (album, a, len - 1);
	
	return album;
}

////////////////////////////////////////////////////////////////////////////////
// path: /music/artists/<artist>/songs
int is_music_artists_artist_songs (const char *path) {
	// contains "/music/artists/ at the beginning
	if( !(strstr (path, "/music/artists") == path)) {
		return 0;
	}
	// skip four "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
	}
	// p now points to "songs"
	// there is no other "/" left in the string
	if ( strtok (p, "/")) {
		return 0;
	}
	// p should be equal to "songs"
	if ( strcmp (p, "songs")) {
		return 0;
	}
	// redundancy check: the string "songs" should trail past the last "/"
	if( !(strcmp (strrchr (path, '/'), "songs") == 0)) {
		return 0;
	}
	
	return 1;
}

int is_in_music_artists_artist_songs (const char *path) {
	// contains "/music/artists/ at the beginning
	if( !(strstr (path, "/music/artists") == path)) {
		return 0;
	}
	// skip four "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// p now points to "songs/_songs_"
	if (! (strstr (p, "songs/") == p)) {
		return 0;
	}
	// skip one "/"
	p = strtok (p, "/");
	if (!p) {
		return 0;
	}
	// *p should not be zero
	if (*p == 0) {
		return 0;
	}
	// p should not contain any more "/"
	if (strtok (p, "/")) {
		return 0;
	}

	return 1;
}

// get: <artist>
char* get_artist_from_music_artists_artist_songs (const char* path) {
	char* artist;
	// skip three "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
	}
	// <artist> is between p and the next occurence of "/"
	int len = strtok (p, "/") - p + 1;
	artist = (char*)malloc(len);
	strncpy (artist, p, len - 1);
	
	return artist;
}

////////////////////////////////////////////////////////////////////////////////
// path: /music/albums
int is_music_albums (const char *path) {
	return (strcmp (path, "/music/albums") == 0);
}

int is_in_music_albums (const char* path) {
	// begins with "/music/albums/"
	if (! (strstr (path, "/music/albums/") == path)) {
		return 0;
	}
	// skip three "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// *p should not be zero
	if (*p == 0) {
		return 0;
	}
	// p should not contain any more "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

////////////////////////////////////////////////////////////////////////////////
// path: /music/albums/<album>
int is_music_albums_album (const char* path) {
	// begins with "/music/albums/"
	if (! (strstr (path, "/music/albums/") == path)) {
		return 0;
	}
	// skip three "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// *p should not be zero
	if (*p == 0) {
		return 0;
	}
	// p should not contain any more "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

int is_in_music_albums_album (const char* path) {
	// begins with "/music/albums/"
	if (! (strstr (path, "/music/albums/") == path)) {
		return 0;
	}
	// skip four "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// *p should not be zero
	if (*p == 0) {
		return 0;
	}
	// p should not contain any more "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

////////////////////////////////////////////////////////////////////////////////
// path: /music/songs
int is_music_songs (const char *path) {
	return (strstr (path, "/music/songs") == 0);
}	

int is_in_music_songs (const char* path) {
	// begins with "/music/songs/"
	if (! (strstr (path, "/music/songs/") == path)) {
		return 0;
	}
	char* p = (char*)((void*)path);
	// skip three "/"
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// *p should not be zero
	if (*p == 0) {
		return 0;
	}
	// p should not contain any more "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

////////////////////////////////////////////////////////////////////////////////
// path: /music/genres
int is_music_genres (const char* path) {
	return (strstr (path, "/music/genres") == 0);
}

int is_in_music_genres (const char* path) {
	// begins with "/music/genres/"
	if (! (strstr (path, "/music/genres/") == path)) {
		return 0;
	}
	char* p = (char*)((void*)path);
	// skip three "/"
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// *p should not be zero
	if (*p == 0) {
		return 0;
	}
	// p should not contain any more "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

////////////////////////////////////////////////////////////////////////////////
// path: /music/genres/<genre>
int is_music_genres_genre (const char* path) {
	// begins with "/music/genres/"
	if ( !(strstr (path, "/music/genres/") == path)) {
		return 0;
	}
	// contains only three "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// length greater than the position of the last occurring '/'
	if ( !(strlen(path) > (strrchr(path, '/') - path))) {
		return 0;
	}
	// redundant check: does not contain another "/"
	if ( strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

int is_in_music_genres_genre (const char* path) {
	// begins with "/music/genres/"
	if ( !(strstr (path, "/music/genres/") == path)) {
		return 0;
	}
	// skip four "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// *p should not be zero
	if (*p == 0) {
		return 0;
	}
	// p should not contain any more "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

// get: <genre>
char* get_genre_from_music_genres_genre (const char* path) {
	char* genre;
	// skip three "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
	}
	int len = strlen(p) + 1;
	genre = (char*)malloc(len);
	strncpy (genre, p, len - 1);
	
	return genre;
}

////////////////////////////////////////////////////////////////////////////////
// path: /music/genres/<genre>/artists
int is_music_genres_genre_artists (const char* path) {
	// must begin with "/music/genres/
	if ( !(strstr (path, "/music/genres/") == path)) {
		return 0;
	}
	// skip four "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// p now points to "artists"
	if (strcmp (p, "artists")) {
		return 0;
	}
	// there is no other "/" left in the string
	if ( strtok (p, "/")) {
		return 0;
	}
	// redundancy check: the string "artists" should trail past the last "/"
	if( !(strcmp (strrchr (path, '/'), "artists") == 0)) {
		return 0;
	}
	
	return 1;
}

int is_in_music_genres_genre_artists (const char* path) {
	// begins with "/music/genres/"
	if ( !(strstr (path, "/music/genres/") == path)) {
		return 0;
	}
	// skip four "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// p now points to artists/_songs_
	if (! (strstr(p, "artists/") == p)) {
		return 0;
	}
	// skip one "/"
	p = strtok (p, "/");
	if (!p) {
		return 0;
	}
	// *p should not be zero
	if (*p == 0) {
		return 0;
	}
	// p should not contain any more "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

// get: <genre>
char* get_genre_from_music_genres_genre_artists (const char* path) {
	char* genre;
	// skip three "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
	}
	// <genre> is between p and the next occurence of "/"
	int len = (strtok (p, "/") - 1) - p + 1;
	genre = (char*)malloc(len);
	strncpy (genre, p, len - 1);
	
	return genre;
}

////////////////////////////////////////////////////////////////////////////////
// path: /music/genres/<genre>/artists/<artist>
int is_music_genres_genre_artists_artist (const char* path) {
	// begins with "/music/genres/"
	if ( !(strstr (path, "/music/genres/") == path)) {
		return 0;
	}
	// skip four "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// p now points to "artists/<artist>"
	if ( !(strstr (p, "artists/") == p)) {
		return 0;
	}
	// p contains only one "/"
	p = strtok (p, "/");
	if (!p) {
		return 0;
	}
	if (strtok (p, "/")) {
		return 0;
	}
	// p must be nonempty
	if (*p == 0) {
		return 0;
	}
	
	return 1;
}

int is_in_music_genres_genre_artists_artist (const char* path) {
	// begins with "/music/genres/"
	if ( !(strstr (path, "/music/genres/") == path)) {
		return 0;
	}
	// skip four "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// p now points to "artists/<artist>/_songs_"
	if ( !(strstr (p, "artists/") == p)) {
		return 0;
	}
	// skip two "/"
	for (int i = 0; i < 2; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// *p should not be zero
	if (*p == 0) {
		return 0;
	}
	// p should not contain any more "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

// get: <genre>
char* get_genre_from_music_genres_genre_artists_artist (const char* path) {
	char* genre;
	// skip three "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
	}
	// <genre> is now between p and the next occurence of "/" in p
	int len = (strtok (p, "/") - 1) - p + 1;
	genre = (char*)malloc(len);
	strncpy (genre, p, len - 1);
	
	return genre;
}

// get: <artist>
char* get_artist_from_music_genres_genre_artists_artist (const char* path) {
	char* artist;
	// skip five "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
	}
	// p now points to <artist>
	int len = strlen(p) + 1;
	artist = (char*)malloc(len);
	strncpy (artist, p, len - 1);
	
	return artist;
}

////////////////////////////////////////////////////////////////////////////////
// path: /music/genres/<genre>/albums
int is_music_genres_genre_albums (const char* path) {
	// begins with "/music/genres/"
	if ( !(strstr (path, "/music/genres/") == path)) {
		return 0;
	}
	// skip four "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// p now points to "albums"
	if (strcmp (p, "albums")) {
		return 0;
	}
	
	return 1;
}

int is_in_music_genres_genre_albums (const char* path) {
	// begins with "/music/genres/"
	if ( !(strstr (path, "/music/genres/") == path)) {
		return 0;
	}
	// skip four "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// p now points to "albums/_songs_"
	if (! (strstr (p, "albums/") == p)) {
		return 0;
	}
	// skip one "/"
	p = strtok (p, "/");
	// *p should not be zero
	if (*p == 0) {
		return 0;
	}
	// p should not contain any more "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

// get: <genre>
char* get_genre_from_music_genres_genre_albums (const char* path) {
	char* genre;
	// skip three "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
	}
	// <genre> is between p and the next occurence of "/"
	int len = (strtok (p, "/") - 1) - p + 1;
	genre = (char*)malloc(len);
	strncpy (genre, p, len - 1);
	
	return genre;
}


////////////////////////////////////////////////////////////////////////////////
// path: /music/genres/<genre>/albums/<album>
int is_music_genres_genre_albums_album (const char* path) {
	// begins with "/music/genres/"
	if ( !(strstr (path, "/music/genres/") == path)) {
		return 0;
	}
	// skip four "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// p now points to "albums/<album>"
	if ( !(strstr (p, "albums") == p)) {
		return 0;
	}
	// p contains only one "/"
	p = strtok (p, "/");
	if (!p) {
		return 0;
	}
	if (strtok (p, "/")) {
		return 0;
	}
	// p must be nonempty
	if (*p == 0) {
		return 0;
	}
	
	return 1;
}

// path: /music/genres/<genre>/albums/<album>/_songs_
int is_in_music_genres_genre_albums_album (const char* path) {
	// begins with "/music/genres/"
	if ( !(strstr (path, "/music/genres/") == path)) {
		return 0;
	}
	// skip four "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// p now points to "albums/<album>/_songs_"
	if ( !(strstr (p, "albums/") == p)) {
		return 0;
	}
	// skip two "/"
	for (int i = 0; i < 2; i++) {
		p = strtok(p, "/");
		if (!p) {
			return 0;
		}
	}
	// *p should not be zero
	if (*p == 0) {
		return 0;
	}
	// p should not contain any more "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

// get: <genre>
char* get_genre_from_music_genres_genre_albums_album (const char* path) {
	char* genre;
	// skip three "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
	}
	// <genre> is now between p and the next occurence of "/" in p
	int len = (strtok (p, "/") - 1) - p + 1;
	genre = (char*)malloc(len);
	strncpy (genre, p, len - 1);
	
	return genre;
}

// get: <album>
char* get_artist_from_music_genres_genre_albums_album (const char* path) {
	char* album;
	// skip five "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
	}
	// p now points to <artist>
	int len = strlen(p) + 1;
	album = (char*)malloc(len);
	strncpy (album, p, len - 1);
	
	return album;
}

////////////////////////////////////////////////////////////////////////////////
// path: /music/genres/<genre>/songs
int is_music_genres_genre_songs (const char* path) {
	// must begin with "/music/genres/
	if ( !(strstr (path, "/music/genres/") == path)) {
		return 0;
	}
	// skip four "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// p now points to "songs"
	if (strcmp (p, "songs")) {
		return 0;
	}
	// there is no other "/" left in the string
	if ( strtok (p, "/")) {
		return 0;
	}
	// redundancy check: the string "songs" should trail past the last "/"
	if( !(strcmp (strrchr (path, '/'), "songs") == 0)) {
		return 0;
	}
	
	return 1;
}

int is_in_music_genres_genre_songs (const char* path) {
	// must begin with "/music/genres/
	if ( !(strstr (path, "/music/genres/") == path)) {
		return 0;
	}
	// skip four "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// p now points to "songs/_songs_"
	if (! (strstr (p, "songs/") == p)) {
		return 0;
	}
	// skip one "/"
	p = strtok (p, "/");
	if (!p) {
		return 0;
	}
	// *p should not be zero
	if (*p == 0) {
		return 0;
	}
	// p should not contain any more "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

// get: <genre>
char* get_genre_from_music_genres_genre_songs (const char* path) {
	char* genre;
	// skip three "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
	}
	// <genre> is between p and the next occurence of "/"
	int len = strtok (p, "/") - p + 1;
	genre = (char*)malloc(len);
	strncpy (genre, p, len - 1);
	
	return genre;
}

////////////////////////////////////////////////////////////////////////////////
// path: /video
int is_video (const char* path) {
	return (strcmp (path, "/video") == 0);
}

int is_in_video (const char* path) {
	// begins with "/video/"
	if (! (strstr (path, "/video/") == path)) {
		return 0;
	}
	char* p = (char*)((void*)path);
	// skip two "/"
	for (int i = 0; i < 2; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// *p should not be zero
	if (*p == 0) {
		return 0;
	}
	// p should not contain any more "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

////////////////////////////////////////////////////////////////////////////////
// path: /video/movies
int is_video_movies(const char* path) {
	return (strcmp (path, "/video/movies/") == 0);
}

int is_in_video_movies (const char* path) {
	// begins with "/video/movies"
	if (! (strstr (path, "/video/movies/") == path)) {
		return 0;
	}
	char* p = (char*)((void*)path);
	// skip three "/"
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// *p should not be zero
	if (*p == 0) {
		return 0;
	}
	// p should not contain any more "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

////////////////////////////////////////////////////////////////////////////////
// path: /video/videoclips
int is_video_videoclips (const char* path) {
	return (strcmp (path, "/video/videoclips") == 0);
}

int is_in_video_videoclips (const char* path) {
	// begins with "/video/videoclips/"
	if (! (strstr (path, "/video/videoclips/") == path)) {
		return 0;
	}
	char* p = (char*)((void*)path);
	// skip three "/"
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// *p should not be zero
	if (*p == 0) {
		return 0;
	}
	// p should not contain any more "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}

////////////////////////////////////////////////////////////////////////////////
// path: /video/videoclips/<artist>
int is_video_videoclips_artist (const char* path) {
	// begins with "/video/videclips/"
	if ( !(strstr (path, "/video/videclips/") == path)) {
		return 0;
	}
	// skip three "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// p does not contain another "/"
	if (strtok (p, "/")) {
		return 0;
	}
	// p must be nonempty
	if (*p == 0) {
		return 0;
	}
	
	return 1;
}

int is_in_video_videoclips_artist (const char* path) {
	// begins with "/video/videclips/"
	if ( !(strstr (path, "/video/videclips/") == path)) {
		return 0;
	}
	// skip four "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 4; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// p does not contain another "/"
	if (strtok (p, "/")) {
		return 0;
	}
	// p must be nonempty
	if (*p == 0) {
		return 0;
	}
	
	return 1;
}

// get: <artist>
char* get_artist_from_video_videoclips_artist (const char* path) {
	char* artist;
	// skip three "/"
	char* p = (char*)((void*)path);
	for (int i = 0; i < 3; i++) {
		p = strtok (p, "/");
	}
	int len = strlen(p) + 1;
	artist = (char*)malloc(len);
	strncpy (artist, p, len - 1);
	
	return artist;
}

////////////////////////////////////////////////////////////////////////////////
// path: /pictures
int is_pictures (const char* path) {
	return (strcmp (path, "/pictures") == 0);
}

int is_in_pictures (const char* path) {
	// begins with "/pictures/"
	if (! (strstr (path, "/pictures/") == path)) {
		return 0;
	}
	char* p = (char*)((void*)path);
	// skip two "/"
	for (int i = 0; i < 2; i++) {
		p = strtok (p, "/");
		if (!p) {
			return 0;
		}
	}
	// *p should not be zero
	if (*p == 0) {
		return 0;
	}
	// p should not contain any more "/"
	if (strtok (p, "/")) {
		return 0;
	}
	
	return 1;
}


// pointer to function
typedef int (*PF)(const char*);
// array of functions which check if path is a directory
PF pf_dir[] = { 
   	// root
   	&is_root,
   	// music
   	&is_music,
   	&is_music_playlists,
   	&is_music_artists,
   	&is_music_artists_artist,
   	&is_music_artists_artist_albums,
   	&is_music_artists_artist_albums_album,
   	&is_music_artists_artist_songs,
   	&is_music_albums,
   	&is_music_albums_album,
   	&is_music_songs,
   	&is_music_genres,
   	&is_music_genres_genre,
   	&is_music_genres_genre_artists,
   	&is_music_genres_genre_artists_artist,
   	&is_music_genres_genre_albums,
   	&is_music_genres_genre_albums_album,
   	&is_music_genres_genre_songs,
   	// video
   	&is_video,
   	&is_video_movies,
   	&is_video_videoclips,
   	&is_video_videoclips_artist,
   	// pictures
   	&is_pictures    	
};

PF pf_reg[] = { 
   	// root
   	&is_in_root,
   	// music
   	&is_in_music,
   	&is_in_music_playlists,
   	&is_in_music_artists,
   	&is_in_music_artists_artist,
   	&is_in_music_artists_artist_albums,
   	&is_in_music_artists_artist_albums_album,
   	&is_in_music_artists_artist_songs,
   	&is_in_music_albums,
   	&is_in_music_albums_album,
   	&is_in_music_songs,
   	&is_in_music_genres,
   	&is_in_music_genres_genre,
   	&is_in_music_genres_genre_artists,
   	&is_in_music_genres_genre_artists_artist,
   	&is_in_music_genres_genre_albums,
   	&is_in_music_genres_genre_albums_album,
   	&is_in_music_genres_genre_songs,
   	// video
   	&is_in_video,
   	&is_in_video_movies,
   	&is_in_video_videoclips,
   	&is_in_video_videoclips_artist,
   	// pictures
   	&is_in_pictures    	
};
// number of pointers to function
const int NUMPF = 23; // TODO


using namespace std;

pthread_mutex_t root_mutex;

static int mfs_getattr (const char* path, struct stat* stbuf);
static int mfs_readdir (const char* path, void* buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info* fi);
static int mfs_open (const char* path, struct fuse_file_info* fi);
static int mfs_read (const char* path, char* buf, size_t size, off_t offset, struct fuse_file_info* fi);
static int mfs_create (const char* path, mode_t mode, struct fuse_file_info* fi);
static int mfs_mkdir (const char* path, mode_t mode);
static int mfs_release (const char* path, struct fuse_file_info* fi);

//--------------------------------------------------------------------------------------------------------------

static int mfs_getattr (const char* path, struct stat* stbuf) {
    //syslog (LOG_DEBUG, "getattr %s\n", path);
    int result = 0;
    memset (stbuf, 0, sizeof (stbuf));
    stbuf->st_nlink = 1;
    // stbuf->st_size
    // TODO
    // check if it is a directory
    int is_valid_dir = 0;
    for (int i = 0; i < NUMPF; i++) {
    	if ( (*pf_dir[i])(path) ) {
    		stbuf->st_mode = S_IFDIR | 0755;
    		is_valid_dir = 1;
    		break;
    	}
    }
	if (!is_valid_dir) {
		// TODO check if it belongs to a valid directory	
		for (int i = 0; i < NUMPF; i++) {
			if ( (*pf_reg[i])(path) ) {
				stbuf->st_mode = S_IFREG | 0755;
				break;
			}
		}
	}
	
    return result;
}

static int mfs_readdir (const char* path, void* buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info* fi) {
	//pthread_mutex_lock (&root_mutex);
	int result = 0;
	//(void) offset;
	//(void fi;
	// add . and .. directory entries
	filler (buf, ".", NULL, 0);
	filler (buf, "..", NULL, 0);
	if (is_root (path)) {
		filler (buf, "music", NULL, 0);
		filler (buf, "video", NULL, 0);
		filler (buf, "pictures", NULL, 0);
	} else if (is_music (path)) {
		filler (buf, "artists", NULL, 0);
		filler (buf, "playlists", NULL, 0);
	} else if (is_music_playlists (path)) {
		// TODO 
		// list all playlists
	} else if (is_music_artists (path)) {
		// TODO
		mysql_query (
			&db, "SELECT id, TRIM(name) FROM Artists WHERE TRIM(name)!=\"\""
		);
		printf ("%s\n", mysql_error(&db));
		MYSQL_RES *result = mysql_store_result (&db);
		if (result!=NULL)
		{
		    MYSQL_ROW data = mysql_fetch_row (result);
		    while (data!=NULL)
		    {
			filler (buf, data[1], NULL, 0);
			printf ("\"%s\"\n", data[1]);
			data = mysql_fetch_row (result);
		    }
		    mysql_free_result (result);
		    return 0;
		}
		// list all artists
	} else if (is_music_artists_artist (path)) {
		// TODO 

	} else if (is_music_artists_artist_albums (path)) {
		// TODO

	} else if (is_music_artists_artist_albums_album (path)) {
		// TODO

	} else if (is_music_artists_artist_songs (path)) {
		// TODO

	} else if (is_music_albums (path)) {
		// TODO

	} else if (is_music_albums_album (path)) {
		// TODO

	} else if (is_music_songs (path)) {
		// TODO
		
	} else if (is_music_genres (path)) {
		// TODO
		
	} else if (is_music_genres_genre (path)) {
		// TODO
		
	} else if (is_music_genres_genre (path)) {
		// TODO
		
	} else if (is_music_genres_genre_artists (path)) {
		// TODO
		
	} else if (is_music_genres_genre_artists_artist (path)) {
		// TODO
		
	} else if (is_music_genres_genre_albums (path)) {
		// TODO
		
	} else if (is_music_genres_genre_albums_album (path)) {
		// TODO
		
	} else if (is_music_genres_songs (path)) {
		// TODO
		
	} else {
		// erronous call
		// result = -ENOENT;
	}
	
	//pthread_mutex_unlock (&root_mutex);
	return result;
}

static int mfs_open (const char* path, struct fuse_file_info* fi) {
	pthread_mutex_lock (&root_mutex);
	int result = 0;
	// get directory name
	char *path_dup1 = strdup (path);
	char *dir_name = dirname (path_dup1);
	// get base name
	char *path_dup2 = strdup (path);
	char *base_name = dirname (path_dup2);
	
	pthread_mutex_unlock (&root_mutex);
	return result;
}

static int mfs_read (const char *path, char* buf, size_t size, off_t  offset, struct fuse_file_info* fi) {
	pthread_mutex_lock (&root_mutex);
	(void) fi;
	int result = 0;
	
	// get directory name
	char *path_dup1 = strdup (path);
	char *dir_name = dirname (path_dup1);
	// get base name
	char *path_dup2 = strdup (path);
	char *base_name = dirname (path_dup2);
	if (strstr (dir_name, "/music") == dir_name) {
		// TODO
		// playback music file or playlist
	} else if (strstr (dir_name, "/movies") == dir_name) {
		// TODO
		// play movie
	} else if (strstr (dir_name, "/pictures") == dir_name) {
		// TODO
		// view pictures
	} else {
		// some other directory -> error
		result = -ENOENT;
	}
		
	pthread_mutex_lock (&root_mutex);
	return result;
}

static int mfs_create (const char* path, mode_t mode, struct fuse_file_info* fi) {
	pthread_mutex_lock (&root_mutex);
	int result = 0;
	
	pthread_mutex_lock (&root_mutex);
	return result;
}

static int mfs_mkdir (const char* path, mode_t mode) {
	pthread_mutex_lock (&root_mutex);
	int result = 0;
	
	pthread_mutex_lock (&root_mutex);
	return result;
}

static int mfs_release (const char* path, struct fuse_file_info* fi) {
	pthread_mutex_lock (&root_mutex);
	int result = 0;
	
	pthread_mutex_lock (&root_mutex);
	return result;
}

//--------------------------------------------------------------------------------------------------------------

static struct fuse_operations functions;

int main (int argc, char *argv[])
{
    mysql_real_connect (&db, "localhost", "root", "", "music", 3306, NULL, 0);
    pthread_mutex_init (&root_mutex, 0);
    functions.getattr = mfs_getattr;
    functions.readdir = mfs_readdir;
    /*functions.open = mfs_open;
    functions.read = mfs_read;
    functions.create = mfs_create;
    functions.release = mfs_release;
    functions.mkdir = mfs_mkdir;*/
    int result = fuse_main (argc, argv, &functions, NULL);
    pthread_mutex_destroy (&root_mutex);
    mysql_close (&db);
    return result;
}

/*

    getattr - inainte de orice open/read
    readdir - listeaza directorul
    open
    read
    release - cand toate programele care accesau fisierul s-au inchis
    

    sfs_open(...) {
	---> baza de date
	// select in baza de date
	
    }
    
    ls /mnt/Media Library/Music/Arists/Britney Spears
    getattr /Music/Artists/Britney Spears
    
    directoarele - 0755
    fisiere - 0644
    
    man 3 stat
    
*/
